package com.powernode.common.aspect;

import com.powernode.common.constant.RedisConstant;
import com.powernode.common.execption.PowerException;
import com.powernode.common.result.ResultCodeEnum;
import com.powernode.common.util.AuthContextHolder;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

/**
 * 用户登录切面类
 *
 *
 */
@Aspect
@Component
public class PowerLoginAspect {

    @Resource
    private RedisTemplate redisTemplate;

    /*

     本质：从redis中根据token获取用户的id
     *  1.获取请求对象
     *  2.获取请求头中的token
     *  3.根据token获取用户id
     *  4.将用户id设置到AuthContextHolder中

        切入点表达式：1.所有的controller方法中  2.带PowerLogin注解的方法
     */
    @Around("execution(* com.powernode.*.controller.*.*(..)) && @annotation(com.powernode.common.annotation.PowerLogin)")
    public Object process(ProceedingJoinPoint pjp) {
        //1.获取请求对象
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();

        //2.获取请求头中的token
        String token = request.getHeader("token");
        if (!StringUtils.hasText(token)) {
            throw new PowerException(ResultCodeEnum.LOGIN_AUTH);
        }

        //3.根据token获取用户id
        String userId = (String)redisTemplate.opsForValue().get(RedisConstant.USER_LOGIN_KEY_PREFIX + token);

        if (!StringUtils.hasText(userId)) {
            throw new PowerException(ResultCodeEnum.LOGIN_AUTH);
        }

        //4.将用户id设置到AuthContextHolder中  ThreadLocal
        AuthContextHolder.setUserId(Long.valueOf(userId));

        try {
            return pjp.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}
